/******************************************************************************************
文件名：loice_master_parser.c
作者：狼狼    版本：Loice    创建日期：2021.9.3
文件描述：
    Loice Master侧解析器（会话）示例。
历史修改记录：
1. 2021-9-3:Loice 狼狼
创建。
2. 2022-5-11:Loice 狼狼
代码公开。
******************************************************************************************/
//+------------------------------------------------------------------------------------------+
//|                                          文件说明
//+------------------------------------------------------------------------------------------+
//|      本文件实现Loice主机协议解析器。
//|      主设备必须考虑对多路从设备进行对接，因此无法避免地需要使用IO多路复用。
//+------------------------------------------------------------------------------------------+
//|                                         头文件包含
//+------------------------------------------------------------------------------------------+
/*|*/#include <stdio.h>
/*|*/#include <string.h>
/*|*/#include <stdlib.h>
/*|*/#include <stdint.h>
/*|*/#include <unistd.h>
/*|*/#include <errno.h>
/*|*/#include <sys/time.h>
/*|*/#include <sys/socket.h>
/*|*/#include <pthread.h>
//|
/*|*/#include "loice_master_parser.h"
/*|*/#include "internal_data.h"
/*|*/#include "data_reg_table.h"
/*|*/#include "project_debug.h"
//+------------------------------------------------------------------------------------------+
//|  函数名称：internal_data_match
//|  功能描述：内部数据类型匹配，查找目标类型的数据处理回调是否被注册
//|  参数说明：ENUM_DATA_TYPE枚举，数据类型值
//|  返回值说明：数据记录表中存在该指令则返回位置，否则返回-1
//|  备注：
//+------------------------------------------------------------------------------------------+
static int internal_data_match(ENUM_DATA_TYPE data_type, uint16_t data_type_value)
{
    int i = 0;
    do
    {
        if(data_reg_table[i].data_type == data_type && data_reg_table[i].data_type_value == data_type_value)
        {
            return i;
        }
        i++;
    }while(data_reg_table[i].data_type != DATA_RESERVED);
    
    return -1;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_data_body_checksum_calcu
//|  功能描述：Loice协议版本1数据体校验和计算
//|  参数说明：指向ST_LOICE_PROTO_VER_1_BODY_MSG结构体的指针，pdata成员数据长度
//|  返回值说明：计算得到的校验和
//|  备注：计算不包括目标校验和成员
//+------------------------------------------------------------------------------------------+
static uint16_t loice_proto_version1_data_body_checksum_calcu(const ST_LOICE_PROTO_VER_1_BODY_MSG *pdata_body, uint32_t data_len)
{
    uint16_t checksum_calcu = 0;
    
    checksum_calcu += pdata_body->data_type;
    checksum_calcu += (uint8_t)((pdata_body->data_type_value & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pdata_body->data_type_value & 0xFF);
    checksum_calcu += (uint8_t)((pdata_body->data_seq & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pdata_body->data_seq & 0xFF);
    if(pdata_body->pdata != NULL && data_len != 0)
    {
        for(uint32_t i = 0; i < data_len; i++)
        {
            checksum_calcu += *(pdata_body->pdata + i);
        }
    }
    
    return checksum_calcu;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_cmd_body_checksum_calcu
//|  功能描述：Loice协议版本1指令体校验和计算
//|  参数说明：指向ST_LOICE_PROTO_VER_1_BODY_CMD结构体的指针，pdata成员数据长度
//|  返回值说明：计算得到的校验和
//|  备注：计算不包括目标校验和成员
//+------------------------------------------------------------------------------------------+
static uint16_t loice_proto_version1_cmd_body_checksum_calcu(const ST_LOICE_PROTO_VER_1_BODY_CMD *pcmd_body, uint32_t data_len)
{
    uint16_t checksum_calcu = 0;
    
    checksum_calcu += pcmd_body->cmd_id;
    checksum_calcu += pcmd_body->reserved1;
    checksum_calcu += (uint8_t)((pcmd_body->cmd_value & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pcmd_body->cmd_value & 0xFF);
    checksum_calcu += (uint8_t)((pcmd_body->reserved2 & 0xFF00) >> 8);
    checksum_calcu += (uint8_t)(pcmd_body->reserved2 & 0xFF);
    
    if(pcmd_body->pdata != NULL && data_len != 0)
    {
        for(uint32_t i = 0; i < data_len; i++)
        {
            checksum_calcu += *(pcmd_body->pdata + i);
        }
    }
    
    return checksum_calcu;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_head_checksum_calcu
//|  功能描述：Loice协议版本1指令首部校验和计算
//|  参数说明：指向ST_LOICE_PROTO_VER_1_HEAD结构体的指针
//|  返回值说明：计算得到的校验和
//|  备注：计算不包括目标首部的校验和字段
//+------------------------------------------------------------------------------------------+
static uint16_t loice_proto_version1_head_checksum_calcu(const ST_LOICE_PROTO_VER_1_HEAD *pmsg_head)
{
    uint16_t checksum_calcu = 0;
    uint8_t *pu8msg_head = (uint8_t *)pmsg_head;
    
    for(int i = 0; i < sizeof(ST_LOICE_PROTO_VER_1_HEAD) - 2; i++)
    {
        checksum_calcu += (uint16_t)(*pu8msg_head);
        pu8msg_head++;
    }
    
    return checksum_calcu;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_kap_msg_head_build
//|  功能描述：Loice协议版本1消息首部-KAP命令构建工具
//|  参数说明：指向本地设备ID数组的指针，输出指令帧首部结构指针，回应信息中“消息类型”字段设置值
//|  返回值说明：无
//|  备注：使用该函数构建的目的ID号字段为0；使用该函数构建的指令类型为KAP_TYPE_NORMAL，即有回应KAP。
//+------------------------------------------------------------------------------------------+
#ifdef ENABLE_KAP
static void loice_proto_version1_kap_msg_head_build(const uint8_t *local_device_id, ST_LOICE_PROTO_VER_1_HEAD *pmsg_head_output)
{
    memset(pmsg_head_output, 0, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
    pmsg_head_output->head[0] = 0x14;
    pmsg_head_output->head[1] = 0xCF;
    pmsg_head_output->head[2] = 0x92;
    pmsg_head_output->head[3] = 0x5A;
    pmsg_head_output->head[4] = 0xA0;
    pmsg_head_output->head[5] = 0xC0;
    pmsg_head_output->head[6] = 0x00;
    pmsg_head_output->head[7] = 0xFF;
    memcpy(pmsg_head_output->source_device_id, local_device_id, 24);
    pmsg_head_output->protocol_version = PARSER_PROTOCOL_1;
    pmsg_head_output->msg_seq          = 0;
    pmsg_head_output->msg_timestamp    = 0;
    pmsg_head_output->payload_length   = 0;
    pmsg_head_output->msg_type         = KAP_TYPE_NORMAL;
    pmsg_head_output->msg_head_check   = loice_proto_version1_head_checksum_calcu(pmsg_head_output);
}
#endif

//+------------------------------------------------------------------------------------------+
//|  函数名称：loice_proto_version1_data_reply_build
//|  功能描述：Loice协议版本1数据回应报文构建工具
//|  参数说明：指向本地设备ID数组的指针，待回应的原指令帧首部结构，回复指令帧首部结构，回应信息中“消息类型”字段设置值
//|  返回值说明：无
//|  备注：回应报文不包含任何长度的荷载部分，仅具有首部字段。
//+------------------------------------------------------------------------------------------+
static void loice_proto_version1_data_reply_build(const uint8_t *local_device_id, 
                                                 const ST_LOICE_PROTO_VER_1_HEAD *pmsg_head_source, 
                                                       ST_LOICE_PROTO_VER_1_HEAD *pmsg_head_reply, 
                                                       ENUM_MESSAGE_TYPE enum_msg_type)
{
    memset(pmsg_head_reply, 0, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
    memcpy(pmsg_head_reply->head, pmsg_head_source->head, 8);
    memcpy(pmsg_head_reply->source_device_id, local_device_id, 24);
    memcpy(pmsg_head_reply->destination_device_id, pmsg_head_source->source_device_id, 24);
    pmsg_head_reply->protocol_version = PARSER_PROTOCOL_1;
    pmsg_head_reply->msg_seq          = pmsg_head_source->msg_seq;
    pmsg_head_reply->msg_timestamp    = 0; /* 时间戳当前未实现 */
    pmsg_head_reply->payload_length   = 0; /* Fixed */
    pmsg_head_reply->msg_type         = enum_msg_type;
    pmsg_head_reply->msg_head_check   = loice_proto_version1_head_checksum_calcu(pmsg_head_reply);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_function_version1_process
//|  功能描述：Loice协议版本1消息接收更新实体
//|  参数说明：指向解析器对象会话结构的指针，用于接收数据的Socket描述符
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回状态码（负值）
//|  备注：调用函数已完成对会话的参数检查，这里无需再次检查。
//|        该函数成功表示当前读取过程没有发生致命错误，即套接字状态正常且数据接收正常。
//|        该函数的返回值需要适配调用模块的后续处理。
//|        该函数仅内部调用。
//+------------------------------------------------------------------------------------------+
#define PFV1P_RECV(p, len) \
do{                                                                                                  \
    ret = recv(sock, p, len, MSG_DONTWAIT|MSG_NOSIGNAL);                                             \
    if(ret < 0)                                                                                      \
    {                                                                                                \
        if((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) return PARSER_SUCCESS;   \
        OUTPUT("[PARSER-ERROR]Session[%d] recv failed with %d!\n", pparser_session->session_id, ret);\
        if(pparser_session->data_body.pdata)free(pparser_session->data_body.pdata);                  \
        return PARSER_EXIT_STAT_RX_ERROR;                                                            \
    }                                                                                                \
    else if(ret == 0)                                                                                \
    {                                                                                                \
        OUTPUT("[PARSER-INFO]Session[%d] disconnected!\n", pparser_session->session_id);             \
        if(pparser_session->data_body.pdata)free(pparser_session->data_body.pdata);                  \
        return PARSER_STAT_DISCONNECT_OR_CLOSE;                                                      \
    }                                                                                                \
}while(0)

static int parser_function_version1_process(ST_PARSER_SESSION *pparser_session, int sock)
{
    int ret = -1;
    switch(pparser_session->state)
    {
        case PARSER_SESSION_STAT_STANDBY:
            PFV1P_RECV(&pparser_session->msg_head.head[0], 1);
            if(pparser_session->msg_head.head[0] == 0x14) pparser_session->state = PARSER_SESSION_STAT_GOTHEAD1;
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD1:
            PFV1P_RECV(&pparser_session->msg_head.head[1], 1);
            (pparser_session->msg_head.head[1] == 0xCF)?(pparser_session->state = PARSER_SESSION_STAT_GOTHEAD2):(pparser_session->state = PARSER_SESSION_STAT_STANDBY);
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD2:
            PFV1P_RECV(&pparser_session->msg_head.head[2], 1);
            (pparser_session->msg_head.head[2] == 0x92)?(pparser_session->state = PARSER_SESSION_STAT_GOTHEAD3):(pparser_session->state = PARSER_SESSION_STAT_STANDBY);
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD3:
            PFV1P_RECV(&pparser_session->msg_head.head[3], 1);
            (pparser_session->msg_head.head[3] == 0x5A)?(pparser_session->state = PARSER_SESSION_STAT_GOTHEAD4):(pparser_session->state = PARSER_SESSION_STAT_STANDBY);
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD4:
            PFV1P_RECV(&pparser_session->msg_head.head[4], 1);
            (pparser_session->msg_head.head[4] == 0xA0)?(pparser_session->state = PARSER_SESSION_STAT_GOTHEAD5):(pparser_session->state = PARSER_SESSION_STAT_STANDBY);
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD5:
            PFV1P_RECV(&pparser_session->msg_head.head[5], 1);
            (pparser_session->msg_head.head[5] == 0xC0)?(pparser_session->state = PARSER_SESSION_STAT_GOTHEAD6):(pparser_session->state = PARSER_SESSION_STAT_STANDBY);
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD6:
            PFV1P_RECV(&pparser_session->msg_head.head[6], 1);
            (pparser_session->msg_head.head[6] == 0x00)?(pparser_session->state = PARSER_SESSION_STAT_GOTHEAD7):(pparser_session->state = PARSER_SESSION_STAT_STANDBY);
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD7:
            PFV1P_RECV(&pparser_session->msg_head.head[7], 1);
            if(pparser_session->msg_head.head[7] == 0xFF)
            {
                pparser_session->state = PARSER_SESSION_STAT_GOTHEAD8;
                pparser_session->next_recv_len = sizeof(ST_LOICE_PROTO_VER_1_HEAD) - 8;
            }
            else
            {
                pparser_session->state = PARSER_SESSION_STAT_STANDBY;
            }
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_GOTHEAD8:
            // ----------------------------------------
            // [说明]首部起始8字节接收完成，开始接收首
            //       部剩余定长数据。
            // ----------------------------------------
            PFV1P_RECV((uint8_t *)&pparser_session->msg_head + sizeof(ST_LOICE_PROTO_VER_1_HEAD) - pparser_session->next_recv_len, pparser_session->next_recv_len);
            pparser_session->next_recv_len -= ret;
            if(pparser_session->next_recv_len == 0) // 接收首部完成
            {
                uint16_t checksum_calcu = loice_proto_version1_head_checksum_calcu(&pparser_session->msg_head);
                if(pparser_session->msg_head.msg_head_check != checksum_calcu)
                {
                    OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Wrong head checksum:0x%.4x Calculated checksum:0x%.4x\n", pparser_session->session_id, pparser_session->msg_head.msg_head_check, checksum_calcu);
                    pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                    return PARSER_SUCCESS;
                }
                pparser_session->state = PARSER_SESSION_STAT_HEAD_CHECK_PASS;
                
                /* 根据首部“消息类型”字段处理后续动作 */
                // ----------------------------------------
                // [说明]在这个case中处理的是没有后续消息体
                //       的数据包。
                // ----------------------------------------
                pparser_session->flag_current_reply = true;
                switch((ENUM_MESSAGE_TYPE)pparser_session->msg_head.msg_type)
                {
                    case DATA_TYPE_NOREPLY:
                        pparser_session->flag_current_reply = false;
                    case DATA_TYPE_NORMAL:
                        /* 切换会话状态 & 设置接收回应使能标志 */
                        pparser_session->state = PARSER_SESSION_STAT_HEAD_CHECK_PASS;
                        pparser_session->next_recv_len = MIN_PAYLOAD_DATA_LENGTH;
                        
                        /* 判断消息荷载长度的合法性 */
                        if(pparser_session->msg_head.payload_length < MIN_PAYLOAD_DATA_LENGTH)
                        {
                            OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Message is too short[%d]!\n", pparser_session->session_id, pparser_session->msg_head.payload_length);
                            pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                        }
                        return PARSER_SUCCESS;
                        
                    case KAP_REPLY_OK:
#ifdef ENABLE_KAP
                        /* 更新本会话的KAP定时器 */
                        gettimeofday(&pparser_session->last_kap_time, NULL);
                        OUTPUT("[PARSER-DEBUG][Session ID:%d]Recv KAP Reply.\n", pparser_session->session_id);
#endif
                        pparser_session->state = PARSER_SESSION_STAT_STANDBY; // 重置接收状态
                    break;
                    case KAP_REPLY_WRONG_ID:
                    case KAP_REPLY_TOO_LONG:
                        /* KAP的正确性应由设计者保证，此错误不应出现，对此数据类型做忽略处理 */
                        pparser_session->state = PARSER_SESSION_STAT_STANDBY; // 重置接收状态
                    //break; // No break here
                    case DATA_TYPE_REPORT_NOREPLY:
                    case DATA_TYPE_REPORT:
                        /* 当前实现中未对主动上报数据的处理，对此数据类型做忽略处理 */
                    //break; // No break here
                    case CMD_REPLY_OK:
                        /* 更新本会话的KAP定时器 */
                        gettimeofday(&pparser_session->last_kap_time, NULL);
                    break;
                    case CMD_REPLY_BUSY:
                    case CMD_REPLY_NOT_FOUND:
                    case CMD_REPLY_WRONG_ID:
                    case CMD_REPLY_OLD_CMD:
                    case CMD_REPLY_TOO_LONG:
                    case CMD_REPLY_TOO_SHORT:
                    case CMD_REPLY_WRONG_CHECK:
                    case CMD_REPLY_WRONG_ARGS:
                    case CMD_REPLY_CMD_EMPTY:
                        /* 当前实现中未对指令回应消息的处理，对此数据类型做忽略处理 */
                    //break; // No break here
                    default:
                        OUTPUT("[PARSER-DEBUG]Parser process[Session ID:%d]:Loice master device does not support message type[%d]!\n", pparser_session->session_id, pparser_session->msg_head.msg_type);
                        pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                        return PARSER_SUCCESS;
                }
            }
            return PARSER_SUCCESS;
            
        case PARSER_SESSION_STAT_HEAD_CHECK_PASS:
            /* 根据首部“消息类型”字段处理后续动作 */
            // ----------------------------------------
            // [说明]在这个case中处理的是有后续消息体的
            //       数据包。
            // [补充]不符合指定类型的数据包在上一状态处
            //       理中已经被丢弃了。
            // ----------------------------------------
            switch((ENUM_MESSAGE_TYPE)pparser_session->msg_head.msg_type)
            {
                case DATA_TYPE_NOREPLY:
                case DATA_TYPE_NORMAL:
                    PFV1P_RECV((uint8_t *)&pparser_session->data_body + MIN_PAYLOAD_DATA_LENGTH - pparser_session->next_recv_len, pparser_session->next_recv_len);
                    pparser_session->next_recv_len -= ret;
                    if(pparser_session->next_recv_len == 0) // 数据体固定字段接收完成
                    {
                        // ----------------------------------------
                        // [说明]前面已经处理了此判断的其他情况
                        // ----------------------------------------
                        if(pparser_session->msg_head.payload_length - MIN_PAYLOAD_DATA_LENGTH == 0)
                        {
                            pparser_session->data_body.pdata = NULL;
                            
                            /* 数据体校验 */
                            uint16_t checksum_calcu = loice_proto_version1_data_body_checksum_calcu(&pparser_session->data_body, MIN_PAYLOAD_DATA_LENGTH);
                            if(checksum_calcu != pparser_session->data_body.msg_body_check)
                            {
                                OUTPUT("[PARSER-WARNING][Session ID:%d][Seq:%d]Data[ID:%d - Value:%d] verification failed[%.4x]!\n",
                                                                                        pparser_session->session_id,
                                                                                        pparser_session->msg_head.msg_seq,
                                                                                        pparser_session->data_body.data_type,
                                                                                        pparser_session->data_body.data_type_value,
                                                                                        checksum_calcu);
                                /* 构建并发送回应报文 */
                                if(pparser_session->flag_current_reply)
                                {
                                    ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                                    loice_proto_version1_data_reply_build(pparser_session->local_device_id, &pparser_session->msg_head, &msg_head_reply, DATA_REPLY_WRONG_CHECK);
                                    if(pparser_session->send_data_reply != NULL)
                                    {
                                        ret = pparser_session->send_data_reply(pparser_session->session_id, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                                        if(ret < 0)
                                        {
                                            OUTPUT("[PARSER-WARNING]Parser[Session ID:%d]:send_data_reply failed with %#x!\n", pparser_session->session_id, ret);
                                            
                                        }
                                    }
                                }
                                
                                /* 重置会话接收状态 */
                                pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                                return PARSER_SUCCESS;
                            }
                            
                            /* 构建内部数据体（空数据体情况） */
                            ST_INTERNAL_DATA internal_data = {0};
                            internal_data.data_type       = pparser_session->data_body.data_type;
                            internal_data.session_id      = pparser_session->session_id;
                            internal_data.data_type_value = pparser_session->data_body.data_type_value;
                            internal_data.msg_seq         = pparser_session->msg_head.msg_seq;
                            internal_data.data_seq        = pparser_session->data_body.data_seq;
                            internal_data.data_length     = 0; /* 此值此处固定为0 */
                            internal_data.pdata           = pparser_session->data_body.pdata;
                            
                            /* TESTPOINT:打印数据（空数据体情况）详情 & 内部转发 */
                            // printf("[PARSER-TEST][Session ID:%d][Seq:%d]Recv data[ID:%d - Value:%d][No.%d][%d]\n",
                                                                                  // internal_data.session_id,
                                                                                  // internal_data.msg_seq,
                                                                                  // internal_data.data_type,
                                                                                  // internal_data.data_type_value,
                                                                                  // internal_data.data_seq,
                                                                                  // 0);
                            // if(internal_data.pdata)free(internal_data.pdata);//Only for test，用于防止内存泄漏
                            write(pparser_session->internal_pipe_write, (uint8_t *)&internal_data, sizeof(ST_INTERNAL_DATA));
                            
                            /* 构建并发送正常回应报文 */
                            if(pparser_session->flag_current_reply)
                            {
                                ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                                loice_proto_version1_data_reply_build(pparser_session->local_device_id, &pparser_session->msg_head, &msg_head_reply, DATA_REPLY_OK);
                                if(pparser_session->send_data_reply != NULL)
                                {
                                    ret = pparser_session->send_data_reply(pparser_session->session_id, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                                    if(ret < 0)
                                    {
                                        OUTPUT("[PARSER-WARNING]Parser[Session ID:%d]:send_data_reply failed with %#x!\n", pparser_session->session_id, ret);
                                        pparser_session->state = PARSER_SESSION_STAT_END;
                                    }
                                }
                            }
                            
                            /* 重置会话接收状态 */
                            pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                        }
                        else
                        {
                            pparser_session->next_recv_len = pparser_session->msg_head.payload_length - MIN_PAYLOAD_DATA_LENGTH;
                            pparser_session->state = PARSER_SESSION_STAT_DATA_BODY_FIXED_DONE;
                        }
                    }
                    return PARSER_SUCCESS;
                default:break;
            }
            return PARSER_SUCCESS;
        
        case PARSER_SESSION_STAT_DATA_BODY_FIXED_DONE:
            
            if(pparser_session->data_body.pdata == NULL)
            {
                pparser_session->data_body.pdata = (uint8_t *)malloc(sizeof(uint8_t) * pparser_session->next_recv_len);
                if(pparser_session->data_body.pdata == NULL)
                {
                    OUTPUT("[PARSER-WARNING]Calloc[%d] for data failed!\n", pparser_session->next_recv_len);
                    pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                    return PARSER_SUCCESS;
                }
            }
            PFV1P_RECV(pparser_session->data_body.pdata + pparser_session->msg_head.payload_length - MIN_PAYLOAD_DATA_LENGTH - pparser_session->next_recv_len, pparser_session->next_recv_len);
            pparser_session->next_recv_len -= ret;
            if(pparser_session->next_recv_len == 0) // 数据体变长部分接收完成
            {
                /* 数据体校验 */
                uint16_t checksum_calcu = loice_proto_version1_data_body_checksum_calcu(&pparser_session->data_body, pparser_session->msg_head.payload_length - MIN_PAYLOAD_DATA_LENGTH);
                if(checksum_calcu != pparser_session->data_body.msg_body_check)
                {
                    OUTPUT("[PARSER-WARNING][Session ID:%d][Seq:%d]Data[ID:%d - Value:%d] verification failed[%.4x]!\n",
                                                                            pparser_session->session_id,
                                                                            pparser_session->msg_head.msg_seq,
                                                                            pparser_session->data_body.data_type,
                                                                            pparser_session->data_body.data_type_value,
                                                                            checksum_calcu);
                    /* 构建并发送回应报文 */
                    if(pparser_session->flag_current_reply)
                    {
                        ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                        loice_proto_version1_data_reply_build(pparser_session->local_device_id, &pparser_session->msg_head, &msg_head_reply, DATA_REPLY_WRONG_CHECK);
                        if(pparser_session->send_data_reply != NULL)
                        {
                            ret = pparser_session->send_data_reply(pparser_session->session_id, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                            if(ret < 0)
                            {
                                OUTPUT("[PARSER-WARNING]Parser[Session ID:%d]:send_data_reply failed with %#x!\n", pparser_session->session_id, ret);
                            }
                        }
                    }
                    
                    /* 释放缓冲区 */
                    if(pparser_session->data_body.pdata)free(pparser_session->data_body.pdata);
                    
                    /* 重置会话接收状态 */
                    pparser_session->state = PARSER_SESSION_STAT_STANDBY;
                    return PARSER_SUCCESS;
                }
                
                /* 构建内部数据体 */
                ST_INTERNAL_DATA internal_data = {0};
                internal_data.data_type       = pparser_session->data_body.data_type;
                internal_data.session_id      = pparser_session->session_id;
                internal_data.data_type_value = pparser_session->data_body.data_type_value;
                internal_data.msg_seq         = pparser_session->msg_head.msg_seq;
                internal_data.data_seq        = pparser_session->data_body.data_seq;
                internal_data.data_length     = pparser_session->msg_head.payload_length - MIN_PAYLOAD_DATA_LENGTH;
                internal_data.pdata           = pparser_session->data_body.pdata;
                
                /* TESTPOINT:打印数据详情 & 内部转发 */
                // printf("[PARSER-TEST][Session ID:%d][Seq:%d]Recv data[ID:%d - Value:%d][No.%d][%d]\n",
                                                                      // internal_data.session_id,
                                                                      // internal_data.msg_seq,
                                                                      // internal_data.data_type,
                                                                      // internal_data.data_type_value,
                                                                      // internal_data.data_seq,
                                                                      // internal_data.data_length);
                // if(internal_data.pdata)free(internal_data.pdata);//Only for test，用于防止内存泄漏
                write(pparser_session->internal_pipe_write, (uint8_t *)&internal_data, sizeof(ST_INTERNAL_DATA));
                
                /* 转发后清除掉当前保存的协议帧信息 */
                memset(&pparser_session->msg_head,  0, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                memset(&pparser_session->data_body, 0, sizeof(ST_LOICE_PROTO_VER_1_BODY_MSG));
                
                /* 构建并发送正常回应报文 */
                if(pparser_session->flag_current_reply)
                {
                    ST_LOICE_PROTO_VER_1_HEAD msg_head_reply;
                    loice_proto_version1_data_reply_build(pparser_session->local_device_id, &pparser_session->msg_head, &msg_head_reply, DATA_REPLY_OK);
                    if(pparser_session->send_data_reply != NULL)
                    {
                        ret = pparser_session->send_data_reply(pparser_session->session_id, (uint8_t *)&msg_head_reply, sizeof(ST_LOICE_PROTO_VER_1_HEAD));
                        if(ret < 0)
                        {
                            OUTPUT("[PARSER-ERROR]Parser[Session ID:%d]:send_data_reply failed with %#x!\n", pparser_session->session_id, ret);
                            pparser_session->state = PARSER_SESSION_STAT_END;
                        }
                    }
                }
                
                /* 重置会话接收状态 */
                pparser_session->state = PARSER_SESSION_STAT_STANDBY;
            }
            return PARSER_SUCCESS;
        default:break;
    }
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：data_forward_process
//|  功能描述：数据转发处理线程
//|  参数说明：指向解析器对象结构的指针
//|  返回值说明：无
//|  备注：此线程同时兼做会话的KAP超时管理
//+------------------------------------------------------------------------------------------+
static void *data_forward_process(void *p)
{
    int ret;
    fd_set readfds;
    struct timeval select_timeout;
    ST_INTERNAL_DATA internal_data = {0};
    ST_PARSER *pparser_obj = (ST_PARSER *)p;
#ifdef ENABLE_KAP
    struct timeval time_now;
#endif
    
    while(pparser_obj->flag_run)
    {
        FD_ZERO(&readfds);
        FD_SET(pparser_obj->internal_pipe[0], &readfds);
        select_timeout.tv_sec  = 1; /* Fixed for KAP */
        select_timeout.tv_usec = 0;
        ret = select(pparser_obj->internal_pipe[0] + 1, &readfds, NULL, NULL, &select_timeout);
        if(ret < 0)
        {
            OUTPUT("[PARSER-WARNING]Select error!\n");
            continue;
        }
        else if(ret == 0)
        {
            //continue; // Nothing to do here
        }
        else
        {
            if(FD_ISSET(pparser_obj->internal_pipe[0], &readfds))
            {
                int index = -1;
                memset(&internal_data, 0, sizeof(ST_INTERNAL_DATA));
                ret = read(pparser_obj->internal_pipe[0], (uint8_t *)&internal_data, sizeof(ST_INTERNAL_DATA));
                if(ret < 0)
                {
                    OUTPUT("[PARSER-WARNING]Read pipe error!\n");
                }
                
                /* 调用数据处理回调函数 */
                index = internal_data_match(internal_data.data_type, internal_data.data_type_value);
                if(index < 0)
                {
                    printf("[PARSER-WARNING][Session ID:%d][Seq:%d]Recv data[ID:%d - Value:%d][No.%d][%d]\n",
                                                                             internal_data.session_id,
                                                                             internal_data.msg_seq,
                                                                             internal_data.data_type,
                                                                             internal_data.data_type_value,
                                                                             internal_data.data_seq,
                                                                             internal_data.data_length);
                    OUTPUT("[PARSER-WARNING]No internal data records were found! Data will be discarded!\n");
                    if(internal_data.pdata != NULL)free(internal_data.pdata);
                }
                else
                {
                    data_reg_table[index].data_process_handle(internal_data);
                }
            }
        }
        
#ifdef ENABLE_KAP
        gettimeofday(&time_now, NULL);
#endif
        for(int i = 0; i < MAX_SESSION_NUM; i++)
        {
            if(pparser_obj->session_list[i] != NULL)
            {
                if(pparser_obj->session_list[i]->state == PARSER_SESSION_STAT_END)
                {
                    pparser_obj->delete_session(pparser_obj, pparser_obj->session_list[i]->session_id);
                }
#ifdef ENABLE_KAP
                else if(time_now.tv_sec - pparser_obj->session_list[i]->last_kap_time.tv_sec > KAP_TIMEOUT)
                {
                    OUTPUT("[PARSER-DEBUG]Parser session[%d] KAP timeout!\n", pparser_obj->session_list[i]->session_id);
                    pparser_obj->kap_timeout_handle(pparser_obj->session_list[i]->session_id); /* 使用回调函数通知上级程序关闭连接 */
                    pparser_obj->delete_session(pparser_obj, pparser_obj->session_list[i]->session_id); /* 删除解析器会话（以使连接管理和解析器会话列表同步） */
                }
                else if(time_now.tv_sec - pparser_obj->session_list[i]->last_kap_time.tv_sec >= KAP_SEND_INTERVAL)
                {
                    /* 构建一个KAP指令 & 发送 */
                    ST_LOICE_PROTO_VER_1_HEAD kap_msg_head = {0};
                    loice_proto_version1_kap_msg_head_build(pparser_obj->session_list[i]->local_device_id, &kap_msg_head);
                    if(pparser_obj->send_data_reply(pparser_obj->session_list[i]->session_id, (uint8_t *)&kap_msg_head, sizeof(ST_LOICE_PROTO_VER_1_HEAD)) < 0)
                    {
                        pparser_obj->delete_session(pparser_obj, pparser_obj->session_list[i]->session_id);
                    }
                    else
                    {
                        OUTPUT("[PARSER-DEBUG][Session ID:%d]Send KAP.\n", pparser_obj->session_list[i]->session_id);
                    }
                }
            }
        }
#endif
    }
    
    pthread_exit(NULL);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：add_session
//|  功能描述：根据会话ID向解析器中增加一个新会话
//|  参数说明：指向解析器对象结构的指针，会话ID
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：
//+------------------------------------------------------------------------------------------+
static int add_session(struct parser * const parser_obj, uint32_t session_id)
{
    /* 参数检查 */
    if(parser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support operation[add_session]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 检查当前解析器实例是否以达到最大会话持有数量 */
    if(parser_obj->session_num >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Session list is full!\n");
        return PARSER_ERROR_SESSION_LIST_FULL;
    }
    
    /* 检查解析器会话是否被重复添加 */
    for(int i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->session_id == session_id)
            {
                OUTPUT("[PARSER-ERROR]The session[ID:%d] has been registered!\n", session_id);
                return PARSER_ERROR_SESSION_REGISTERED;
            }
        }
    }
    
    /* 申请解析器会话结构空间 */
    ST_PARSER_SESSION *ptmp = (ST_PARSER_SESSION *)calloc(1, sizeof(ST_PARSER_SESSION));
    if(ptmp == NULL)
    {
        OUTPUT("[PARSER-ERROR]Calloc[%ld] ST_PARSER_SESSION structure failed!\n", sizeof(ST_PARSER_SESSION));
        return PARSER_ERROR_MALLOC;
    }
    
    /* 更新解析器会话信息 */
    ptmp->session_id          = session_id;
    ptmp->state               = PARSER_SESSION_STAT_STANDBY;
    ptmp->internal_pipe_write = parser_obj->internal_pipe[1];
    ptmp->next_recv_len       = 0;
    ptmp->pdata_body          = NULL;
    ptmp->send_data_reply     = parser_obj->send_data_reply;
    memcpy(ptmp->local_device_id, parser_obj->local_device_id, 28);
    
    /* 初始化KAP时间 */
    gettimeofday(&ptmp->last_kap_time, NULL);
    
    /* 将解析器会话示例增加到解析器会话列表 */
    // ----------------------------------------
    // [说明]前面已经判断列表是否已满，此处无需
    //       再次判断。
    // ----------------------------------------
    pthread_mutex_lock(&parser_obj->mutex);
    for(int i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] == NULL)
        {
            parser_obj->session_list[i] = ptmp;
            parser_obj->session_num++;
            OUTPUT("[PARSER-INFO]Add session[%d] to parser session list[%d]!\n", session_id, i);
            break;
        }
    }
    pthread_mutex_unlock(&parser_obj->mutex);
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：delete_session
//|  功能描述：根据会话ID从解析器中删除指定的会话
//|  参数说明：指向解析器对象结构的指针，会话ID
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：
//+------------------------------------------------------------------------------------------+
static int delete_session(struct parser * const parser_obj, uint32_t session_id)
{
    int i = 0;
    
    /* 参数检查 */
    if(parser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support operation[delete_session]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 检查解析器会话持有量 */
    if(parser_obj->session_num == 0)
    {
        OUTPUT("[PARSER-ERROR]Session list is empty!\n");
        return PARSER_ERROR_SESSION_LIST_EMPTY;
    }
    
    pthread_mutex_lock(&parser_obj->mutex);
    
    /* 在解析器会话列表中查找指定会话 */
    for(i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->session_id == session_id)
            {
                OUTPUT("[PARSER-DEBUG]Find session[%d] in list[%d]!\n", session_id, i);
                
                if(parser_obj->session_list[i]->state == PARSER_SESSION_STAT_INIT)
                {
                    OUTPUT("[PARSER-WARNING]The session state[%d] does not support this operation!\n", parser_obj->session_list[i]->state);
                    pthread_mutex_unlock(&parser_obj->mutex);
                    return PARSER_ERROR_UNEXPECT_STATE;
                }
                
                /* 修改解析器会话状态 */
                parser_obj->session_list[i]->state = PARSER_SESSION_STAT_END;
                
                break;
            }
        }
    }
    if(i >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Can't find session[%d] in parser session list!\n", session_id);
        pthread_mutex_unlock(&parser_obj->mutex);
        return PARSER_ERROR_SESSION_NON_EXISTENT;
    }
    
    /* 释放该会话占用的资源 */
    if(parser_obj->session_list[i]->pdata_body != NULL)
    {
        free(parser_obj->session_list[i]->pdata_body);
    }
    free(parser_obj->session_list[i]);
    
    /* 从解析器会话列表中删除对该会话的记录 */
    parser_obj->session_list[i] = NULL;
    parser_obj->session_num--;
    
    pthread_mutex_unlock(&parser_obj->mutex);
    
    OUTPUT("[PARSER-INFO]Delete session[%d] from parser session list[%d]!\n", session_id, i);
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：cmd_trans
//|  功能描述：封装指令结构为Loice格式
//|  参数说明：指向内部指令体结构的指针，指令体中pargs所指数据长度，用于输出发送数据的指针和数据长度，指令是否要求回应
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：当pargs成员为NULL时，args_len必须设置为0。
//|        上级函数需主动释放发送数据指针指向的堆空间，以免造成内存泄漏！
//|        如需对指令回应做处理，需在接收函数中实现对指令回应类消息的处理机制。
//+------------------------------------------------------------------------------------------+
static int cmd_trans(struct parser * const parser_obj, const ST_INTERNAL_CMD *pinternal_cmd, uint32_t args_len, uint8_t **ppmsg, uint32_t *pmsg_len, bool need_reply)
{
    /* 参数检查 */
    if(parser_obj == NULL || pinternal_cmd == NULL || pmsg_len == NULL || ppmsg == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(*ppmsg != NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 1 pointer must be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The parser state[%d] does not support operation[cmd_trans]!\n", parser_obj->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    if(pinternal_cmd == NULL && args_len != 0)
    {
        OUTPUT("[PARSER-ERROR]Illegal parameters!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    
    if(args_len > MAX_PAYLOAD_LENGTH - MIN_PAYLOAD_LENGTH)
    {
        OUTPUT("[PARSER-ERROR]Command is too long!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    
    /* 按解析器当前的工作协议构建发送报文 */
    switch(parser_obj->protocol_version)
    {
        case PARSER_PROTOCOL_1:
        {
            /* 申请缓存空间 */
            uint8_t *ptmp = (uint8_t *)calloc(1, sizeof(ST_LOICE_PROTO_VER_1_HEAD) + MIN_PAYLOAD_LENGTH + args_len);
            if(ptmp == NULL)
            {
                OUTPUT("[PARSER-ERROR]Calloc[%ld] failed!\n", sizeof(ST_LOICE_PROTO_VER_1_HEAD) + MIN_PAYLOAD_LENGTH + args_len);
                return PARSER_ERROR_MALLOC;
            }
            
            /* 填充头部信息 */
            ST_LOICE_PROTO_VER_1_HEAD *pmsg_head = (ST_LOICE_PROTO_VER_1_HEAD *)ptmp;
            pmsg_head->head[0] = 0x14;
            pmsg_head->head[1] = 0xCF;
            pmsg_head->head[2] = 0x92;
            pmsg_head->head[3] = 0x5A;
            pmsg_head->head[4] = 0xA0;
            pmsg_head->head[5] = 0xC0;
            pmsg_head->head[6] = 0x00;
            pmsg_head->head[7] = 0xFF;
            memcpy(pmsg_head->source_device_id, parser_obj->local_device_id, 28);
            pmsg_head->protocol_version = PARSER_PROTOCOL_1;
            pmsg_head->payload_length   = MIN_PAYLOAD_LENGTH + args_len;
            if(need_reply)
            {
                pmsg_head->msg_type     = CMD_TYPE_NORMAL;
            }
            else
            {
                pmsg_head->msg_type     = CMD_TYPE_NOREPLY;
            }
            pmsg_head->msg_head_check   = loice_proto_version1_head_checksum_calcu(pmsg_head);
            
            /* 填充荷载信息 */
            ST_LOICE_PROTO_VER_1_BODY_CMD *pcmd_body = (ST_LOICE_PROTO_VER_1_BODY_CMD *)(ptmp + sizeof(ST_LOICE_PROTO_VER_1_HEAD));
            pcmd_body->cmd_id    = (uint8_t)pinternal_cmd->cmd_id;
            pcmd_body->cmd_value = pinternal_cmd->cmd_value;
            if(pinternal_cmd->pargs != NULL)
            {
                memcpy(pcmd_body->pdata, pinternal_cmd->pargs, args_len);
            }
            pcmd_body->cmd_body_check = loice_proto_version1_cmd_body_checksum_calcu(pcmd_body, args_len);
            
            /* 输出数据信息 */
            *ppmsg    = ptmp;
            *pmsg_len = sizeof(ST_LOICE_PROTO_VER_1_HEAD) + MIN_PAYLOAD_LENGTH + args_len;
        }
        break;
        default:
            OUTPUT("[PARSER-ERROR]The parser is set to work on an unknown protocol version[%d]!\n", parser_obj->protocol_version);
            return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_function
//|  功能描述：启动对指定会话的解析
//|  参数说明：指向解析器对象结构的指针，会话ID，可用于读取数据的Socket描述符
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回状态码（负值）
//|  备注：该函数成功表示当前读取过程没有发生致命错误，即套接字状态正常且数据接收正常。
//|        该函数的返回值需要适配调用模块的后续处理。
//+------------------------------------------------------------------------------------------+
static int parser_function(struct parser * const parser_obj, uint32_t session_id, int sock)
{
    int i = 0;
    int ret   = -1;
    int index = -1;
    
    /* 参数检查 */
    if(parser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Pointer is NULL!\n");
        return PARSER_STAT_ILLEGAL_PARAM;
    }
    if(parser_obj->state != PARSER_STAT_OK)
    {
        OUTPUT("[PARSER-ERROR]The parser state[%d] does not support operation[parser_function]!\n", parser_obj->state);
        return PARSER_STAT_PARSER_UNEXPECT_STATE;
    }
    
    pthread_mutex_lock(&parser_obj->mutex);
    
    /* 在解析器会话列表中查找指定会话，获取其位置 */
    for(i = 0; i < MAX_SESSION_NUM; i++)
    {
        if(parser_obj->session_list[i] != NULL)
        {
            if(parser_obj->session_list[i]->session_id == session_id)
            {
                index = i;
                break;
            }
        }
    }
    if(i >= MAX_SESSION_NUM)
    {
        OUTPUT("[PARSER-ERROR]Can't find session[%d] in parser session list!\n", session_id);
        pthread_mutex_unlock(&parser_obj->mutex);
        return PARSER_STAT_SESSION_NON_EXISTENT;
    }
    
    /* 检查会话当前的状态 */
    if(parser_obj->session_list[index]->state == PARSER_SESSION_STAT_END || 
       parser_obj->session_list[index]->state == PARSER_SESSION_STAT_INIT)
    {
        OUTPUT("[PARSER-ERROR]The parser session state[%d] does not support operation[parser_function]!\n",
                                                                   parser_obj->session_list[index]->state);
        pthread_mutex_unlock(&parser_obj->mutex);
        return PARSER_STAT_SESSION_UNEXPECT_STATE;
    }
    
    /* 检查协议版本 */
    switch(parser_obj->protocol_version)
    {
        case PARSER_PROTOCOL_1:
            ret = parser_function_version1_process(parser_obj->session_list[index], sock);
            pthread_mutex_unlock(&parser_obj->mutex);
            return ret;
        break;
        default:
            OUTPUT("[PARSER-ERROR]There is no matching protocol!\n");
            pthread_mutex_unlock(&parser_obj->mutex);
            return PARSER_STAT_UNSUPPORT_PROTOCOL;
        break;
    }
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_create
//|  功能描述：初始化主设备解析器对象结构，创建主设备解析器实例
//|  参数说明：用于输出解析器对象结构的指针、使用的通信协议版本、本地设备ID、回应数据发送接口和会话超时回调
//|  返回值说明：成功返回PARSER_SUCCESS，pparser_obj指针输出指向对象结构体的空间；
//|              失败返回错误码（负值）
//|  备注：若本地设备ID指针为NULL，则本地设备ID将被设置为保留的全0字段。
//|        若创建解析器失败，不会修改原指针的值。
//|        本地设备号数组长度必须不小于28字节。
//+------------------------------------------------------------------------------------------+
int parser_create(ST_PARSER **ppparser_obj, ENUM_PARSER_PROCOTOL_VERSION version,
                                const uint8_t *plocal_device_id,
                                int (*send_data_reply)(uint32_t session_id, const uint8_t *pdata, uint32_t data_len),
                                void (*kap_timeout_handle)(uint32_t session_id))
{
    /* 参数检查 */
    if(version == PARSER_PROTOCOL_INIT)
    {
        OUTPUT("[PARSER-ERROR]The version[%d] must be a positive integer!\n", version);
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(ppparser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 2 pointer can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(*ppparser_obj != NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 1 pointer must be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
#ifdef ENABLE_KAP
    if(kap_timeout_handle == NULL)
    {
        OUTPUT("[PARSER-ERROR]if KAP is enabled, kap_timeout_handle can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
#endif
    
    /* 申请解析器结构空间 */
    ST_PARSER *ptmp = (ST_PARSER *)calloc(1, sizeof(ST_PARSER));
    if(ptmp == NULL)
    {
        OUTPUT("[PARSER-ERROR]Calloc[%ld] ST_PARSER structure failed!\n", sizeof(ST_PARSER));
        return PARSER_ERROR_MALLOC;
    }
    
    /* 创建解析器数据转发线程 */
    ptmp->flag_run = true;
    if(pthread_create(&ptmp->tid, NULL, data_forward_process, (void *)ptmp) != 0)
    {
        OUTPUT("[PARSER-ERROR]Create data forward process thread failed!\n");
        free(ptmp);
        return PARSER_ERROR_THREAD;
    }
    
    /* 设置解析器配置参数 & 更新解析器对象结构 */
    ptmp->state            = PARSER_STAT_OK;
    ptmp->protocol_version = version;
    
    // ----------------------------------------
    // [说明]当plocal_device_id为NULL时，本地设
    //       备号为全0，calloc调用为其做了初始化。
    // ----------------------------------------
    if(plocal_device_id != NULL)
    {
        memcpy(ptmp->local_device_id, plocal_device_id, 28);
    }
    
    ptmp->add_session     = add_session;
    ptmp->delete_session  = delete_session;
    ptmp->cmd_trans       = cmd_trans;
    ptmp->parser_function = parser_function;
    ptmp->send_data_reply = send_data_reply;
    ptmp->kap_timeout_handle = kap_timeout_handle;
    pthread_mutex_init(&ptmp->mutex, NULL);
    
    /* 创建数据转发内部管道 */
    pipe(ptmp->internal_pipe);
    
    *ppparser_obj = ptmp;
    
    OUTPUT("[PARSER-INFO]Parser[Version ID:%d] created.\n", ptmp->protocol_version);
    
    return PARSER_SUCCESS;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：parser_destroy
//|  功能描述：去初始化主设备解析器对象结构，释放其占用的资源
//|  参数说明：指向解析器对象结构指针的指针
//|  返回值说明：成功返回PARSER_SUCCESS，失败返回错误码（负值）
//|  备注：若销毁解析器成功，原指针的值会被置为NULL。
//|        销毁解析器将同时销毁其管理的所有解析会话。
//+------------------------------------------------------------------------------------------+
int parser_destroy(ST_PARSER **ppparser_obj)
{
    /* 参数检查 */
    if(ppparser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 2 pointer can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if(*ppparser_obj == NULL)
    {
        OUTPUT("[PARSER-ERROR]Level 1 pointer can't be NULL!\n");
        return PARSER_ERROR_ILLEGAL_PARAM;
    }
    if((*ppparser_obj)->state != PARSER_STAT_OK && (*ppparser_obj)->state != PARSER_STAT_TEMP)
    {
        OUTPUT("[PARSER-ERROR]The current state[%d] does not support this operation[parser_destroy]!\n", (*ppparser_obj)->state);
        return PARSER_ERROR_UNEXPECT_STATE;
    }
    
    /* 修改解析器实例状态以锁死解析器 */
    (*ppparser_obj)->state = PARSER_STAT_TEMP;
    
    /* 结束解析器数据转发处理线程 */
    (*ppparser_obj)->flag_run = false;
    pthread_join((*ppparser_obj)->tid, NULL);
    
    /* 遍历解析器会话列表，结束已有会话，回收会话资源 */
    // ----------------------------------------
    // [说明]使用当前的方法，对会话列表的轮询会
    //       发生两次，但考虑到本函数一般处于程
    //       序退出过程中，因此效率问题被忽略。
    // ----------------------------------------
    for(int i = 0; i < MAX_SESSION_NUM; i++)
    {
        if((*ppparser_obj)->session_list[i] != NULL)
        {
            delete_session(*ppparser_obj, (*ppparser_obj)->session_list[i]->session_id);
        }
    }
    
    /* 释放解析器本身所占资源 */
    close((*ppparser_obj)->internal_pipe[0]);
    close((*ppparser_obj)->internal_pipe[1]);
    pthread_mutex_destroy(&(*ppparser_obj)->mutex);
    free(*ppparser_obj);
    *ppparser_obj = NULL;
    
    return PARSER_SUCCESS;
}
